{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "nbsphinx": "hidden"
   },
   "source": [
    "This notebook is part of the `clifford` documentation: https://clifford.readthedocs.io/."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# The  Algebra Of Space (G3)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "In this notebook, we give a more detailed look at how to use `clifford`, using the algebra of three dimensional space as a context."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  Setup"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "First, we import clifford as `cf`, and instantiate a three dimensional geometric algebra using `Cl()` ([docs](../generated/clifford.Cl.rst))."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import clifford as cf\n",
    "\n",
    "layout, blades = cf.Cl(3)  # creates a 3-dimensional clifford algebra"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "\n",
    "Given a three dimensional GA with the orthonormal basis,\n",
    "\n",
    "$$e_{i}\\cdot e_{j}=\\delta_{ij}$$\n",
    " \n",
    "\n",
    "The basis consists of scalars, three vectors, three bivectors, and a trivector. \n",
    "\n",
    "$$\\{\\hspace{0.5em}\n",
    "\\underbrace{\\hspace{0.5em}\\alpha,\\hspace{0.5em}}_{\\mbox{scalar}}\\hspace{0.5em}\n",
    "\\underbrace{\\hspace{0.5em}e_{1},\\hspace{1.5em}e_{2},\\hspace{1.5em}e_{3},\\hspace{0.5em}}_{\\mbox{vectors}}\\hspace{0.5em}\n",
    "\\underbrace{\\hspace{0.5em}e_{12},\\hspace{1.5em}e_{23},\\hspace{1.5em}e_{13},\\hspace{0.5em}}_{\\mbox{bivectors}}\\hspace{0.5em}\n",
    "\\underbrace{\\hspace{0.5em}e_{123}\\hspace{0.5em}}_{\\text{trivector}}\n",
    "\\hspace{0.5em}\n",
    "\\}$$\n",
    "\n",
    "`Cl()`  creates the algebra and returns a `layout` and `blades`. The `layout` holds information and functions related this instance of `G3`,  and the `blades` is a dictionary which contains the basis blades, indexed by their string representations,\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "blades "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You may wish to explicitly assign the blades to variables like so, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e1 = blades['e1']\n",
    "e2 = blades['e2']\n",
    "# etc ..."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Or, if you're lazy and just working in an interactive session you can use `locals()` to update your namespace with all of the blades at once."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "locals().update(blades)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Now, all the blades have been defined in the local namespace"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e3, e123"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  Basics"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Products"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The basic products   are available"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e1*e2  # geometric product"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e1|e2  # inner product "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e1^e2  # outer product"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e1^e2^e3  # even more outer products"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Defects in Precedence"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Python's operator precedence makes the outer product evaluate after addition. This requires the use of parentheses when using outer products. For example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "e1^e2 + e2^e3  # fail, evaluates as "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(e1^e2) + (e2^e3)  # correct"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Also the inner product of a scalar and a Multivector is  0, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "4|e1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "So for scalars, use the outer product or geometric product instead"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "4*e1"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Multivectors"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Multivectors can be defined in terms of the basis blades. For example you can construct a rotor as a sum of a scalar and bivector, like so "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import math\n",
    "\n",
    "theta = math.pi/4\n",
    "R = math.cos(theta) - math.sin(theta)*e23\n",
    "R"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also mix grades without any reason\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A = 1 + 2*e1 + 3*e12 + 4*e123\n",
    "A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reversion"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The reversion operator is accomplished with the tilde `~` in front of the Multivector on which it acts"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "~A"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Grade Projection"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Taking a projection onto a specific grade $n$  of a Multivector is usually written \n",
    "\n",
    "$$\\langle A \\rangle _n$$\n",
    "\n",
    "can be done by using soft brackets, like so"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A(0)  # get grade-0 elements of R"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A(1)  # get grade-1 elements of R"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A(2)  # you get it"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Magnitude"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Using the reversion and grade projection operators, we can define the magnitude of $A$\n",
    "\n",
    "$$|A|^2 = \\langle A\\tilde{A}\\rangle$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "(A*~A)(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This is  done in the `abs()` operator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "abs(A)**2"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Inverse"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The inverse of a Multivector is defined as $A^{-1}A=1$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.inv()*A"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "A.inv()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Dual"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "The dual of a multivector $A$ can be defined as \n",
    "$$AI^{-1}$$\n",
    "\n",
    "Where, $I$ is the pseudoscalar for the GA. In $G_3$, the dual of a vector is a bivector, "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 1*e1 + 2*e2 + 3*e3 \n",
    "a.dual()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "###  Pretty, Ugly, and  Display Precision"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can toggle pretty printing with with `pretty()`  or `ugly()`. `ugly` returns an eval-able string."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cf.ugly()\n",
    "A.inv() "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You can also change the displayed precision"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "cf.pretty(precision=2)\n",
    "\n",
    "A.inv()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "This does not effect the internal precision used for computations."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Applications"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Reflections\n",
    "\n",
    "![reflection on vector](../_static/reflection_on_vector.svg)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Reflecting a vector $c$ about a normalized vector $n$ is pretty simple, \n",
    "\n",
    "$$ c \\rightarrow ncn$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "c = e1+e2+e3    # a vector\n",
    "n = e1          # the reflector\n",
    "n*c*n           # reflect `a` in hyperplane normal to `n`"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Because we have the `inv()` available, we can equally well reflect in un-normalized vectors using, \n",
    "$$ a \\rightarrow nan^{-1}$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = e1+e2+e3    # the vector\n",
    "n = 3*e1        # the reflector\n",
    "n*a*n.inv()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Reflections can also be made with respect to the a 'hyperplane normal to the vector $n$', in this case the formula is negated\n",
    "$$c \\rightarrow -ncn^{-1}$$"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Rotations"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "A vector can be rotated using the formula\n",
    "$$ a \\rightarrow Ra\\tilde{R}$$\n",
    "\n",
    "Where $R$ is a rotor. A rotor can be defined by multiple reflections, \n",
    "\n",
    "$$R=mn$$ \n",
    "\n",
    "or by a plane and an angle,\n",
    "\n",
    "$$R = e^{-\\frac{\\theta}{2}\\hat{B}}$$\n",
    "\n",
    "For example"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R = math.e**(-math.pi/4*e12)  # enacts rotation by pi/2 \n",
    "R"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R*e1*~R  # rotate e1 by pi/2 in the e12-plane"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Some Ways to use Functions "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Maybe we want to define a function which can return rotor of some angle $\\theta$ in the $e_{12}$-plane,\n",
    "\n",
    "$$ R_{12} = e^{-\\frac{\\theta}{2}e_{12}} $$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R12 = lambda theta: math.e**(-theta/2*e12)\n",
    "R12(math.pi/2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "And use it like this"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "a = e1+e2+e3\n",
    "R = R12(math.pi/2)\n",
    "R*a*~R"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You might as well make the angle argument a bivector, so that you can control the plane of rotation as well as the angle\n",
    "\n",
    "$$ R_B = e^{-\\frac{B}{2}}$$\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R_B = lambda B: math.e**(-B/2)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then you could do "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R12 = R_B(math.pi/4*e12)\n",
    "R23 = R_B(math.pi/5*e23)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "or"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R_B(math.pi/6*(e23+e12))  # rotor enacting a pi/6-rotation in the e23+e12-plane"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Maybe you want to define a function which returns a *function* that enacts a specified rotation,  \n",
    "\n",
    "$$f(B) \\rightarrow \\underline{R_B}(a) = R_Ba\\tilde{R_B}$$\n",
    "\n",
    "This just saves you having to write out the sandwich product, which is nice if you are cascading a bunch of rotors, like so\n",
    "$$ \\underline{R_C}( \\underline{R_B}( \\underline{R_A}(a)))$$\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def R_factory(B):\n",
    "    def apply_rotation(a):\n",
    "        R = math.e**(-B/2)\n",
    "        return R*a*~R\n",
    "    return apply_rotation\n",
    "    \n",
    "R = R_factory(math.pi/6*(e23+e12))  # this returns a function \n",
    "R(a)  # which acts on a vector "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Then you can do things like "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "R12 = R_factory(math.pi/3*e12)\n",
    "R23 = R_factory(math.pi/3*e23)\n",
    "R13 = R_factory(math.pi/3*e13)\n",
    "\n",
    "R12(R23(R13(a)))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "To make cascading a sequence of rotations  as concise as possible, we could define a function which takes a list of bivectors $A,B,C,..$ , and enacts the sequence of rotations which they represent on a some vector $x$. \n",
    "\n",
    "$$f(A,B,C,x) = \\underline{R_A}  (\\underline{R_B} (\\underline{R_C}(x)))$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from functools import reduce  \n",
    "\n",
    "# a sequence of rotations\n",
    "def R_seq(*args):\n",
    "    *Bs, x = args\n",
    "    R_lst = [math.e**(-B/2) for B in Bs]  # create list of Rotors from list of Bivectors\n",
    "    R = reduce(cf.gp, R_lst)          # apply the geometric product to list of Rotors\n",
    "    return R*x*~R\n",
    "\n",
    "# rotation sequence by  pi/2-in-e12 THEN pi/2-in-e23\n",
    "R_seq(math.pi/2*e23, math.pi/2*e12, e1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "##  Changing Basis Names"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If you want to use different names for your basis as opposed to e's with numbers, supply the `Cl()` with a list of `names`. For example for a two dimensional GA,"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "layout, blades = cf.Cl(2, names=['','x','y','i'])\n",
    "\n",
    "blades"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "locals().update(blades)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "1*x + 2*y"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "1 + 4*i"
   ]
  }
 ],
 "metadata": {
  "anaconda-cloud": {},
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 1
}
